// ==UserScript==
// @name         离线网页保存助手-电脑端
// @namespace    http://tampermonkey.net/
// @version      0.9
// @description  类似SingleFile的功能，将网页保存为单一HTML文件，支持移动端和特殊网站
// @author       Cursor
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_download
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_setClipboard
// @grant        GM_openInTab
// @grant        unsafeWindow
// @grant        GM_addStyle
// @icon          https://gitee.com/selling-surprises/Greasyfork-Script-repository/raw/main/%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC/%E4%BF%9D%E5%AD%98%E4%B8%BA%E7%A6%BB%E7%BA%BF%E7%BD%91%E9%A1%B5/saveWebPageOffline.png
// @connect      *
// @run-at       document-idle
// @updateURL     https://gitee.com/selling-surprises/Greasyfork-Script-repository/raw/main/%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC/%E4%BF%9D%E5%AD%98%E4%B8%BA%E7%A6%BB%E7%BA%BF%E7%BD%91%E9%A1%B5/%E4%BF%9D%E5%AD%98%E4%B8%BA%E7%A6%BB%E7%BA%BF%E7%BD%91%E9%A1%B5-%E7%94%B5%E8%84%91%E7%AB%AF.user.js
// ==/UserScript==

(function() {
    'use strict';

    // 版本信息
    const VERSION = '0.9';
    const UPDATE_INFO = '移除多余下载模式，添加离线信息显示控制，修复离线信息无法点开问题';

    // 注册菜单项
    GM_registerMenuCommand("保存为离线网页", savePageAsHTML);
    GM_registerMenuCommand("切换离线信息显示", toggleInfoDisplay);
    GM_registerMenuCommand("网页元素选择器", startElementPicker);

    // 主函数：保存页面为HTML文件
    function savePageAsHTML() {
        // 显示保存中提示
        showSavingMessage();
        
        // 设置全局超时控制
        const timeoutDuration = 60000; // 60秒超时
        let isTimedOut = false;
        const timeoutId = setTimeout(() => {
            isTimedOut = true;
            showErrorMessage("保存超时，请重试或尝试保存较小的页面");
        }, timeoutDuration);
        
        // 开始处理页面
        processPage().then(html => {
            clearTimeout(timeoutId);
            if (!isTimedOut) {
                // 下载HTML
                downloadHTML(html);
            }
        }).catch(error => {
            clearTimeout(timeoutId);
            console.error("保存网页时出错:", error);
            showErrorMessage("保存失败: " + error.message);
        });
    }
    
    // 切换离线信息显示
    function toggleInfoDisplay() {
        const currentSetting = GM_getValue('showInfoDisplay', true); // 默认显示
        GM_setValue('showInfoDisplay', !currentSetting);
        
        if (currentSetting) {
            showSimpleMessage('已关闭离线页面信息显示');
        } else {
            showSimpleMessage('已开启离线页面信息显示');
        }
    }

    // 显示简单消息
    function showSimpleMessage(message) {
        const messageDiv = document.createElement('div');
        messageDiv.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 15px 20px;
            border-radius: 5px;
            z-index: 9999999;
            font-family: Arial, sans-serif;
            font-size: 14px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
        `;
        messageDiv.textContent = message;
        document.body.appendChild(messageDiv);
        
        setTimeout(() => {
            messageDiv.remove();
        }, 3000);
    }

    // 显示正在保存的消息
    function showSavingMessage() {
        const messageDiv = document.createElement('div');
        messageDiv.id = 'offline-saver-message';
        messageDiv.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 15px 20px;
            border-radius: 5px;
            z-index: 9999999;
            font-family: Arial, sans-serif;
            font-size: 14px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
        `;
        messageDiv.textContent = '正在准备离线网页，请稍候...';
        document.body.appendChild(messageDiv);
    }

    // 显示错误消息
    function showErrorMessage(message) {
        const messageDiv = document.getElementById('offline-saver-message');
        if (messageDiv) {
            messageDiv.textContent = message;
            messageDiv.style.background = 'rgba(200, 0, 0, 0.8)';
            setTimeout(() => {
                messageDiv.remove();
            }, 5000);
        }
        
        // 也显示一个通知
        if (typeof GM_notification !== 'undefined') {
            GM_notification({
                text: message,
                title: '离线网页保存助手',
                timeout: 5000
            });
        }
    }

    // ======================== 元素选择器模块 ========================
    // 元素选择器状态
    let pickerActive = false;
    let highlightedElement = null;
    let pickerRoot = null;
    let pickerOverlay = null;
    
    // 启动元素选择器
    function startElementPicker() {
        // 如果已经激活，不重复启动
        if (pickerActive) return;
        
        pickerActive = true;
        showSimpleMessage('元素选择器已启动，点击要拦截的元素');
        
        // 创建透明覆盖层以捕获所有元素包括高层级广告
        pickerOverlay = document.createElement('div');
        pickerOverlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: transparent;
            z-index: 2147483647; /* 最高层级 */
            cursor: crosshair;
        `;
        document.body.appendChild(pickerOverlay);
        
        // 创建选择器UI
        createPickerUI();
        
        // 设置事件处理
        pickerOverlay.addEventListener('mousemove', onPickerMouseMove);
        pickerOverlay.addEventListener('click', onPickerClick);
        
        // 右键退出
        pickerOverlay.addEventListener('contextmenu', function(e) {
            e.preventDefault();
            stopElementPicker();
            return false;
        });
        
        // ESC键退出
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape' && pickerActive) {
                stopElementPicker();
            }
        });
    }
    
    // 创建选择器UI
    function createPickerUI() {
        // 创建选择器UI容器
        pickerRoot = document.createElement('div');
        pickerRoot.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            z-index: 2147483647;
            padding: 5px 10px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            font-family: Arial, sans-serif;
            font-size: 12px;
            border-radius: 0 0 4px 0;
            pointer-events: none;
        `;
        
        // 设置UI内容
        pickerRoot.innerHTML = `
            <div style="margin: 5px 0;">
                <p style="margin: 0 0 5px 0;">正在选择元素，点击要拦截的元素</p>
                <p style="margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 300px;" id="element-picker-selected-element">鼠标悬停在元素上显示选择器</p>
            </div>
            <div style="margin: 5px 0; font-size: 10px;">
                <p style="margin: 0;">按ESC键或右键点击取消</p>
            </div>
        `;
        
        document.body.appendChild(pickerRoot);
    }
    
    // 处理选择器鼠标移动
    function onPickerMouseMove(event) {
        if (!pickerActive) return;
        
        // 获取鼠标下方元素，忽略覆盖层和UI自身
        const x = event.clientX;
        const y = event.clientY;
        pickerOverlay.style.pointerEvents = 'none';
        const element = document.elementFromPoint(x, y);
        pickerOverlay.style.pointerEvents = 'auto';
        
        // 忽略选择器UI
        if (element && element !== pickerOverlay && !pickerRoot.contains(element)) {
            highlightElement(element);
        }
    }
    
    // 处理选择器点击事件
    function onPickerClick(event) {
        if (!pickerActive) return;
        
        event.preventDefault();
        event.stopPropagation();
        
        // 获取点击位置元素
        const x = event.clientX;
        const y = event.clientY;
        pickerOverlay.style.pointerEvents = 'none';
        const element = document.elementFromPoint(x, y);
        pickerOverlay.style.pointerEvents = 'auto';
        
        if (element && element !== pickerOverlay && !pickerRoot.contains(element)) {
            confirmElementBlock(element);
            stopElementPicker();
        }
        
        return false;
    }
    
    // 停止元素选择器
    function stopElementPicker() {
        // 移除高亮
        if (highlightedElement) {
            highlightedElement.style.outline = '';
            highlightedElement = null;
        }
        
        // 移除选择器UI
        if (pickerRoot) {
            document.body.removeChild(pickerRoot);
            pickerRoot = null;
        }
        
        // 移除覆盖层
        if (pickerOverlay) {
            // 移除事件监听
            pickerOverlay.removeEventListener('mousemove', onPickerMouseMove);
            pickerOverlay.removeEventListener('click', onPickerClick);
            
            document.body.removeChild(pickerOverlay);
            pickerOverlay = null;
        }
        
        // 重置状态
        pickerActive = false;
    }
    
    // 高亮元素
    function highlightElement(element) {
        // 移除之前的高亮
        if (highlightedElement) {
            highlightedElement.style.outline = '';
        }
        
        // 高亮新元素
        highlightedElement = element;
        highlightedElement.style.outline = '2px solid #f00';
        
        // 更新UI显示
        updatePickerUI(element);
    }
    
    // 更新选择器UI
    function updatePickerUI(element) {
        if (!pickerRoot) return;
        
        const selector = generateSelector(element);
        const elementInfo = document.getElementById('element-picker-selected-element');
        
        if (elementInfo) {
            elementInfo.textContent = selector;
        }
    }
    
    // 生成CSS选择器 - 增强版，更好地处理广告元素
    function generateSelector(element) {
        if (!element || element === document.body || element === document.documentElement) {
            return 'body';
        }

        // 检查是否是广告弹窗类元素
        const isPopupAd = isAdPopup(element);
        if (isPopupAd) {
            return isPopupAd; // 返回特殊处理的选择器
        }
        
        // 1. 尝试使用ID
        if (element.id) {
            const idSelector = `#${element.id}`;
            // 确认这个ID是唯一的
            if (document.querySelectorAll(idSelector).length === 1) {
                return idSelector;
            }
        }
        
        // 2. 尝试使用类名组合
        if (element.className && typeof element.className === 'string') {
            const classes = element.className.trim().split(/\s+/);
            if (classes.length > 0 && classes[0]) {
                // 先尝试使用所有类名
                if (classes.length > 1) {
                    const classSelector = `.${classes.join('.')}`;
                    // 检查是否唯一
                    if (document.querySelectorAll(classSelector).length === 1) {
                        return classSelector;
                    }
                }
                
                // 然后尝试使用单个类名（从最有特征性的开始）
                for (const cls of classes) {
                    // 广告相关的类名优先使用
                    if (/ad|banner|popup|modal|dialog|overlay/i.test(cls)) {
                        const singleClassSelector = `.${cls}`;
                        if (document.querySelectorAll(singleClassSelector).length < 5) {
                            return singleClassSelector;
                        }
                    }
                }
                
                // 最后尝试第一个类名
                const singleClassSelector = `.${classes[0]}`;
                if (document.querySelectorAll(singleClassSelector).length < 3) {
                    return singleClassSelector;
                }
            }
        }
        
        // 3. 尝试使用标签+文本内容（针对广告文字）
        const tagName = element.tagName.toLowerCase();
        const text = element.textContent ? element.textContent.trim() : '';
        if (text && /广告|赞助|推广|ad|sponsor|advertisement/i.test(text)) {
            // 使用:has选择器或:contains选择器
            return `${tagName}:has-text(${text.substring(0, 10)})`;
        }
        
        // 4. 尝试使用HTML结构特征
        if (hasAdAttributes(element)) {
            let attributeSelector = tagName;
            
            // 添加常见的广告特征属性
            const adAttributes = hasAdAttributes(element);
            for (const attr in adAttributes) {
                if (adAttributes[attr]) {
                    attributeSelector += `[${attr}="${adAttributes[attr]}"]`;
                }
            }
            
            return attributeSelector;
        }
        
        // 5. 如果有高z-index或fixed/absolute定位，可能是广告
        const computedStyle = window.getComputedStyle(element);
        const position = computedStyle.position;
        const zIndex = parseInt(computedStyle.zIndex);
        
        if ((position === 'fixed' || position === 'absolute') && zIndex > 1000) {
            return `${tagName}[style*="position: ${position}"]`;
        }
        
        // 6. 如果父元素有ID，使用它作为基础
        const parent = element.parentElement;
        if (parent && parent.id && parent !== document.body) {
            return `#${parent.id} > ${tagName}`;
        }
        
        // 7. 最后，创建更精确的路径选择器
        return createPathSelector(element);
    }
    
    // 检查元素是否有广告特征属性
    function hasAdAttributes(element) {
        const adAttributeMap = {};
        const attributes = [
            'data-ad', 'data-ad-client', 'data-ad-slot', 'data-adtest', 'data-ad-unit',
            'data-adblock', 'data-adbox', 'data-advertisement', 'aria-label', 'role'
        ];
        
        for (const attr of attributes) {
            if (element.hasAttribute(attr)) {
                adAttributeMap[attr] = element.getAttribute(attr);
            }
        }
        
        return Object.keys(adAttributeMap).length > 0 ? adAttributeMap : false;
    }
    
    // 检查元素是否是广告弹窗
    function isAdPopup(element) {
        // 检查元素及其祖先元素
        let current = element;
        let level = 0;
        
        while (current && level < 3) {
            // 检查元素内容是否包含广告标记
            if (current.textContent && /^广告$|^AD$|^\s*广告\s*$/.test(current.textContent.trim())) {
                return `*:has(${current.tagName.toLowerCase()}:contains(广告))`;
            }
            
            // 检查样式特征是否是弹窗
            const style = window.getComputedStyle(current);
            if (
                (style.position === 'fixed' || style.position === 'absolute') &&
                parseInt(style.zIndex) > 1000 &&
                current.offsetWidth > 100 && current.offsetHeight > 100
            ) {
                // 查找元素内是否有关闭按钮
                const closeButtons = current.querySelectorAll('button, [role="button"], [aria-label*="关闭"], [aria-label*="close"]');
                if (closeButtons.length > 0) {
                    return `${current.tagName.toLowerCase()}[style*="position: ${style.position}"]`;
                }
            }
            
            // 检查类名和ID是否包含广告标记
            if (current.className && /ad|popup|modal|dialog/i.test(current.className)) {
                return `.${current.className.split(' ')[0]}`;
            }
            
            if (current.id && /ad|popup|modal|dialog/i.test(current.id)) {
                return `#${current.id}`;
            }
            
            current = current.parentElement;
            level++;
        }
        
        return false;
    }
    
    // 确认屏蔽元素
    function confirmElementBlock(element) {
        if (!element) return;
        
        // 生成基本选择器
        const selector = generateSelector(element);
        
        // 显示确认对话框
        showBlockConfirmDialog(element, selector);
    }
    
    // 显示屏蔽确认对话框
    function showBlockConfirmDialog(element, selector) {
        // 创建确认对话框
        const dialog = document.createElement('div');
        dialog.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            border: 1px solid #ccc;
            border-radius: 8px;
            padding: 20px;
            z-index: 2147483647;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            width: 350px;
            max-width: 90%;
            font-family: Arial, sans-serif;
            color: #333;
        `;
        
        // 设置对话框内容
        dialog.innerHTML = `
            <h3 style="margin-top: 0; color: #333; font-size: 16px;">拦截网页元素</h3>
            <div style="margin: 10px 0;">
                <p style="margin: 5px 0; font-size: 14px;">是否在保存网页时移除这个元素？</p>
                <p style="margin: 5px 0; font-size: 12px; color: #666; word-break: break-all; max-height: 60px; overflow-y: auto;">${selector}</p>
            </div>
            <div style="margin: 10px 0;">
                <label style="display: flex; align-items: center; user-select: none; cursor: pointer; margin-bottom: 8px;">
                    <input type="checkbox" id="block-immediate" checked style="margin-right: 8px;"> 
                    <span>立即隐藏元素</span>
                </label>
            </div>
            <div style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 15px;">
                <button id="block-cancel" style="padding: 8px 12px; border: none; background: #f0f0f0; border-radius: 4px; cursor: pointer;">取消</button>
                <button id="block-confirm" style="padding: 8px 12px; border: none; background: #4285f4; color: white; border-radius: 4px; cursor: pointer;">确认</button>
            </div>
        `;
        
        // 添加对话框到页面
        document.body.appendChild(dialog);
        
        // 获取对话框中的元素
        const immediateCheckbox = document.getElementById('block-immediate');
        const cancelButton = document.getElementById('block-cancel');
        const confirmButton = document.getElementById('block-confirm');
        
        // 取消按钮事件
        cancelButton.addEventListener('click', function() {
            document.body.removeChild(dialog);
            // 恢复元素显示
            element.style.display = '';
            element.style.visibility = '';
            element.style.opacity = '';
        });
        
        // 确认按钮事件
        confirmButton.addEventListener('click', function() {
            // 立即隐藏元素
            if (immediateCheckbox.checked) {
                element.style.display = 'none';
            }
            
            // 添加到临时会话的选择器列表中
            // 这些选择器只在当前网页保存过程中有效
            if (!window._tempHiddenSelectors) {
                window._tempHiddenSelectors = [];
            }
            
            // 添加选择器到临时列表
            if (!window._tempHiddenSelectors.includes(selector)) {
                window._tempHiddenSelectors.push(selector);
                showSimpleMessage(`已添加元素到当前保存会话`);
            }
            
            // 关闭对话框
            document.body.removeChild(dialog);
        });
    }
    
    // 创建路径选择器
    function createPathSelector(element) {
        let selector = element.tagName.toLowerCase();
        let current = element;
        let path = [];
        
        // 向上最多4层
        for (let i = 0; i < 4; i++) {
            const parent = current.parentElement;
            if (!parent || parent === document.body || parent === document.documentElement) {
                break;
            }
            
            if (parent.id) {
                path.unshift(`#${parent.id}`);
                break;
            } else if (parent.className && typeof parent.className === 'string') {
                const classes = parent.className.trim().split(/\s+/);
                if (classes.length > 0 && classes[0]) {
                    path.unshift(`.${classes[0]}`);
                    break;
                }
            } else {
                const siblings = Array.from(parent.children).filter(c => c.tagName === current.tagName);
                if (siblings.length > 1) {
                    const index = siblings.indexOf(current) + 1;
                    path.unshift(`${parent.tagName.toLowerCase()} > ${current.tagName.toLowerCase()}:nth-of-type(${index})`);
                } else {
                    path.unshift(parent.tagName.toLowerCase());
                }
            }
            
            current = parent;
        }
        
        // 如果没有构建路径，使用标签和位置
        if (path.length === 0) {
            const index = Array.from(element.parentElement.children).indexOf(element) + 1;
            return `${element.tagName.toLowerCase()}:nth-child(${index})`;
        }
        
        return path.join(' > ') + (path.length ? ' > ' : '') + selector;
    }

    // 修改处理页面函数以应用自定义选择器
    async function processPage() {
        // 创建页面副本
        const docClone = document.cloneNode(true);
        
        // 清理临时消息元素
        const messageElem = docClone.getElementById('offline-saver-message');
        if (messageElem) {
            messageElem.remove();
        }
        
        // 确保正确的中文编码
        ensureProperEncoding(docClone);
        
        // 应用自定义屏蔽规则 - 在处理前实施，避免下载不必要资源
        applyCustomBlockRules(docClone);
        
        // 处理所有样式表
        await processStylesheets(docClone);
        
        // 处理所有图片
        await processImages(docClone);
        
        // 处理所有脚本
        processScripts(docClone);
        
        // 处理所有链接
        processLinks(docClone);
        
        // 移除保存按钮（如果存在）
        const saveButton = docClone.getElementById('offline-save-button');
        if (saveButton) {
            saveButton.remove();
        }
        
        // 清理不必要的元素
        cleanupDocument(docClone);
        
        // 处理被广告屏蔽的元素
        handleBlockedAds(docClone);
        
        // 添加保存信息
        addSaveInfo(docClone);
        
        // 获取处理后的HTML
        const html = getDocumentHTML(docClone);
        
        return html;
    }

    // 应用自定义屏蔽规则
    function applyCustomBlockRules(doc) {
        // 获取保存的自定义选择器
        const customSelectors = GM_getValue('customHiddenSelectors', []);
        
        // 获取临时会话中的选择器
        const tempSelectors = window._tempHiddenSelectors || [];
        
        // 合并所有需要处理的选择器
        const allSelectors = [...customSelectors, ...tempSelectors];
        
        if (allSelectors.length === 0) return;
        
        // 应用每个选择器
        allSelectors.forEach(selector => {
            try {
                const elements = doc.querySelectorAll(selector);
                elements.forEach(el => {
                    if (el) {
                        el.remove(); // 直接从DOM中移除
                    }
                });
            } catch (e) {
                console.error(`应用选择器 "${selector}" 时出错:`, e);
            }
        });
    }

    // 处理页面，转换为单一HTML文件
    async function processPage() {
        // 创建页面副本
        const docClone = document.cloneNode(true);
        
        // 清理临时消息元素
        const messageElem = docClone.getElementById('offline-saver-message');
        if (messageElem) {
            messageElem.remove();
        }
        
        // 确保正确的中文编码
        ensureProperEncoding(docClone);
        
        // 处理所有样式表
        await processStylesheets(docClone);
        
        // 处理所有图片
        await processImages(docClone);
        
        // 处理所有脚本
        processScripts(docClone);
        
        // 处理所有链接
        processLinks(docClone);
        
        // 移除保存按钮（如果存在）
        const saveButton = docClone.getElementById('offline-save-button');
        if (saveButton) {
            saveButton.remove();
        }
        
        // 清理不必要的元素
        cleanupDocument(docClone);
        
        // 处理被广告屏蔽的元素
        handleBlockedAds(docClone);
        
        // 添加保存信息
        addSaveInfo(docClone);
        
        // 获取处理后的HTML
        const html = getDocumentHTML(docClone);
        
        return html;
    }
    
    // 确保正确的中文编码
    function ensureProperEncoding(doc) {
        // 确保文档有正确的charset声明
        let metaCharset = doc.querySelector('meta[charset]');
        if (!metaCharset) {
            metaCharset = doc.querySelector('meta[http-equiv="Content-Type"]');
            if (!metaCharset) {
                // 如果没有编码标记，添加一个UTF-8编码标记
                metaCharset = doc.createElement('meta');
                metaCharset.setAttribute('charset', 'UTF-8');
                const head = doc.getElementsByTagName('head')[0];
                if (head && head.firstChild) {
                    head.insertBefore(metaCharset, head.firstChild);
                } else if (head) {
                    head.appendChild(metaCharset);
                }
            }
        } else {
            // 强制设为UTF-8以确保中文正常显示
            metaCharset.setAttribute('charset', 'UTF-8');
        }
        
        // 检查HTML标签的lang属性
        const htmlTag = doc.getElementsByTagName('html')[0];
        if (htmlTag) {
            const currentLang = htmlTag.getAttribute('lang');
            // 如果没有lang属性并且页面中包含中文，添加中文lang
            if (!currentLang && /[\u4e00-\u9fa5]/.test(doc.body.innerText)) {
                htmlTag.setAttribute('lang', 'zh-CN');
            }
        }
    }
    
    // 处理被广告屏蔽器隐藏的元素
    function handleBlockedAds(doc) {
        // 寻找所有可能被uBlock Origin屏蔽的元素
        const possibleAdSelectors = [
            '.adsbygoogle',
            '[id*="google_ads"]',
            '[id*="aswift"]',
            '[id*="ad-"]',
            '[class*="ad-"]',
            '[class*="ads-"]',
            '[id*="ads-"]',
            'ins[class*="adsbygoogle"]',
            'div[data-ad]',
            'div[id*="div-gpt-ad"]',
            'div[class*="banner"]',
            'iframe[src*="googleads"]',
            'iframe[src*="doubleclick"]',
            'iframe[data-src*="ads"]',
            'iframe[id*="google_ads"]',
            '[style*="z-index: 2147483647"]',
            '[class*="advert"]',
            '[id*="sponsor"]',
            '[class*="sponsor"]'
        ];
        
        // 使用组合选择器一次查询多个元素
        try {
            const adElements = Array.from(doc.querySelectorAll(possibleAdSelectors.join(',')));
            
            // 移除广告元素
            adElements.forEach(el => {
                // 仅移除实际可见的广告元素，避免误删内容
                if (el.offsetWidth > 0 || el.offsetHeight > 0) {
                    const computedStyle = getComputedStyle(el);
                    // 检查元素是否被隐藏（uBlock会将广告标记为display:none）
                    if (computedStyle.display === 'none' || 
                        computedStyle.visibility === 'hidden' || 
                        computedStyle.opacity === '0') {
                        el.remove();
                    }
                } else {
                    // 没有尺寸的元素可能是隐藏的广告
                    el.remove();
                }
            });
            
            // 寻找并移除uBlock Origin添加的占位符
            const placeholders = Array.from(doc.querySelectorAll('div[style*="background-color: rgba(0, 0, 0, 0); position: absolute;"][style*="height: "][style*="width: "]'));
            placeholders.forEach(el => el.remove());
            
            // 清理空div（可能是广告的容器）
            const emptyDivs = Array.from(doc.querySelectorAll('div:empty'));
            emptyDivs.forEach(div => {
                // 检查是否有广告相关的类或ID
                const className = div.className || '';
                const id = div.id || '';
                if (/ad|ads|banner|sponsor|promo/i.test(className) || /ad|ads|banner|sponsor|promo/i.test(id)) {
                    div.remove();
                }
            });
        } catch (e) {
            console.error("处理广告元素时出错:", e);
        }
    }

    // 处理样式表
    async function processStylesheets(doc) {
        const styleSheets = Array.from(doc.querySelectorAll('link[rel="stylesheet"]'));
        
        for (const stylesheet of styleSheets) {
            try {
                const href = stylesheet.getAttribute('href');
                if (!href || href.startsWith('data:')) continue;
                
                const fullUrl = new URL(href, window.location.href).href;
                const cssText = await fetchResource(fullUrl);
                
                // 创建内联样式元素
                const style = doc.createElement('style');
                style.textContent = await processCSSText(cssText, fullUrl);
                
                // 替换原始样式表链接
                stylesheet.parentNode.replaceChild(style, stylesheet);
            } catch (error) {
                console.error("处理样式表时出错:", error);
                // 创建一个空的样式元素作为替代，避免布局错误
                const style = doc.createElement('style');
                style.textContent = `/* 无法加载样式: ${stylesheet.getAttribute('href')} */`;
                stylesheet.parentNode.replaceChild(style, stylesheet);
            }
        }
        
        // 处理内联样式表中的URL
        const styles = Array.from(doc.querySelectorAll('style'));
        for (const style of styles) {
            try {
                style.textContent = await processCSSText(style.textContent, window.location.href);
            } catch (error) {
                console.error("处理内联样式时出错:", error);
            }
        }
    }

    // 处理CSS文本中的URL
    async function processCSSText(cssText, baseUrl) {
        // 查找CSS中的所有URL
        const urlRegex = /url\(\s*(['"]?)([^'"()]+)\1\s*\)/g;
        const urls = [...cssText.matchAll(urlRegex)];
        
        for (const match of urls) {
            try {
                const fullUrlMatch = match[0];
                const quote = match[1];
                const urlPath = match[2];
                
                // 如果已经是data URL，则跳过
                if (urlPath.startsWith('data:')) continue;
                
                // 构造完整URL
                const fullUrl = new URL(urlPath, baseUrl).href;
                
                // 获取资源并转换为base64
                const base64Data = await fetchResourceAsBase64(fullUrl);
                
                // 替换原URL为data URL
                cssText = cssText.replace(fullUrlMatch, `url(${quote}${base64Data}${quote})`);
            } catch (error) {
                console.error("处理CSS中的URL时出错:", error);
                // 如果无法获取资源，保留原始URL
            }
        }
        
        return cssText;
    }

    // 处理图片
    async function processImages(doc) {
        const images = Array.from(doc.querySelectorAll('img'));
        const maxConcurrent = 5; // 限制并发请求数量
        const chunks = [];
        
        // 将图片分组处理，每组maxConcurrent个
        for (let i = 0; i < images.length; i += maxConcurrent) {
            chunks.push(images.slice(i, i + maxConcurrent));
        }
        
        // 按组依次处理图片
        for (const chunk of chunks) {
            await Promise.allSettled(chunk.map(async (img) => {
                try {
                    const src = img.getAttribute('src');
                    if (!src || src.startsWith('data:')) return;
                    
                    const fullUrl = new URL(src, window.location.href).href;
                    const base64Data = await fetchResourceAsBase64(fullUrl);
                    
                    // 替换图片源为base64
                    img.setAttribute('src', base64Data);
                    
                    // 移除srcset以确保使用我们的src
                    if (img.hasAttribute('srcset')) {
                        img.removeAttribute('srcset');
                    }
                    
                    // 移除懒加载相关属性
                    if (img.hasAttribute('data-src')) {
                        img.removeAttribute('data-src');
                    }
                    if (img.hasAttribute('loading')) {
                        img.removeAttribute('loading');
                    }
                } catch (error) {
                    console.error("处理图片时出错:", error);
                    // 如果图片加载失败，添加一个占位符
                    if (img.hasAttribute('alt')) {
                        img.setAttribute('title', '图片加载失败: ' + img.getAttribute('alt'));
                    }
                }
            }));
            
            // 添加小延迟，避免请求过于密集
            await new Promise(resolve => setTimeout(resolve, 100));
        }
        
        // 处理背景图片在行内样式中的情况
        const elementsWithBgImage = Array.from(doc.querySelectorAll('*[style*="background"]'));
        for (const element of elementsWithBgImage) {
            try {
                const style = element.getAttribute('style');
                if (!style) continue;
                
                const urlRegex = /url\(\s*(['"]?)([^'"()]+)\1\s*\)/g;
                const urls = [...style.matchAll(urlRegex)];
                
                let newStyle = style;
                for (const match of urls) {
                    const fullUrlMatch = match[0];
                    const quote = match[1];
                    const urlPath = match[2];
                    
                    if (urlPath.startsWith('data:')) continue;
                    
                    const fullUrl = new URL(urlPath, window.location.href).href;
                    const base64Data = await fetchResourceAsBase64(fullUrl);
                    
                    newStyle = newStyle.replace(fullUrlMatch, `url(${quote}${base64Data}${quote})`);
                }
                
                element.setAttribute('style', newStyle);
            } catch (error) {
                console.error("处理背景图片时出错:", error);
            }
        }
    }

    // 处理脚本
    function processScripts(doc) {
        // 对于离线浏览，通常我们会移除大多数脚本以提高安全性和减小文件大小
        // 但是保留某些基本功能脚本

        // 获取所有外部脚本
        const externalScripts = Array.from(doc.querySelectorAll('script[src]'));
        
        // 移除所有外部脚本
        for (const script of externalScripts) {
            script.remove();
        }
        
        // 可选：保留某些必要的内联脚本，例如保留那些不依赖外部资源的UI交互脚本
        const inlineScripts = Array.from(doc.querySelectorAll('script:not([src])'));
        for (const script of inlineScripts) {
            // 如果脚本包含某些关键词（如广告、分析、跟踪等），则移除
            if (/google|analytics|tracker|tracking|ads|advertisement|facebook|twitter/i.test(script.textContent)) {
                script.remove();
            }
        }
    }

    // 处理链接
    function processLinks(doc) {
        // 将所有外部链接添加target="_blank"以在新窗口打开
        const links = Array.from(doc.querySelectorAll('a[href]'));
        
        for (const link of links) {
            const href = link.getAttribute('href');
            if (!href) continue;
            
            // 跳过锚点链接和javascript:链接
            if (href.startsWith('#') || href.startsWith('javascript:')) continue;
            
            // 如果是外部链接，添加target="_blank"
            if (href.startsWith('http') || href.startsWith('//')) {
                link.setAttribute('target', '_blank');
                
                // 添加rel="noopener noreferrer"以提高安全性
                link.setAttribute('rel', 'noopener noreferrer');
            }
        }
    }

    // 添加保存信息
    function addSaveInfo(doc) {
        // 检查用户是否禁用了信息显示
        if (GM_getValue('showInfoDisplay', true) === false) {
            return; // 如果用户禁用了信息显示，则不添加信息栏
        }
        
        const infoDiv = doc.createElement('div');
        infoDiv.id = 'offline-save-info';
        infoDiv.style.cssText = `
            position: fixed;
            bottom: 0;
            right: 0;
            background: rgba(0, 0, 0, 0.6);
            color: white;
            padding: 5px 10px;
            font-size: 12px;
            border-top-left-radius: 5px;
            z-index: 9999;
            opacity: 0.5;
            transition: opacity 0.3s, transform 0.3s;
            transform: translateY(0);
            cursor: pointer;
            font-family: Arial, sans-serif;
        `;
        
        const today = new Date();
        const saveDate = today.toLocaleString();
        const originalUrl = window.location.href;
        const originalTitle = document.title;
        
        // 创建一个小标签
        const miniInfoDiv = doc.createElement('div');
        miniInfoDiv.style.cssText = `
            padding: 3px 6px;
            text-align: center;
        `;
        miniInfoDiv.textContent = '↑ 离线页面信息';
        
        // 创建详细信息容器
        const detailsDiv = doc.createElement('div');
        detailsDiv.id = 'offline-save-details';
        detailsDiv.style.cssText = `
            padding: 5px;
            display: none;
        `;
        
        detailsDiv.innerHTML = `
            <div>标题: ${originalTitle}</div>
            <div>来源: <a href="${originalUrl}" target="_blank" style="color:#aaf;text-decoration:underline;">${originalUrl}</a></div>
            <div>保存时间: ${saveDate}</div>
            <div style="text-align:right;font-size:10px;margin-top:5px;">
                <a href="#" id="remove-info-bar" style="color:#aaf;text-decoration:underline;">关闭</a>
            </div>
        `;
        
        // 添加到主div
        infoDiv.appendChild(detailsDiv);
        infoDiv.appendChild(miniInfoDiv);
        
        // 添加鼠标事件
        infoDiv.addEventListener('mouseenter', function() {
            this.style.opacity = '1';
        });
        
        infoDiv.addEventListener('mouseleave', function() {
            if (detailsDiv.style.display === 'none') {
                this.style.opacity = '0.5';
            }
        });
        
        // 添加点击事件（展开/收起）
        infoDiv.addEventListener('click', function(e) {
            // 阻止事件冒泡，确保点击事件被正确处理
            e.stopPropagation();
            
            // 检查是否点击了关闭按钮
            if (e.target.id === 'remove-info-bar') {
                e.preventDefault();
                this.remove();
                return;
            }
            
            if (detailsDiv.style.display === 'none') {
                detailsDiv.style.display = 'block';
                miniInfoDiv.textContent = '↓ 收起信息';
                this.style.opacity = '1';
            } else {
                detailsDiv.style.display = 'none';
                miniInfoDiv.textContent = '↑ 离线页面信息';
                this.style.opacity = '0.5';
            }
        });
        
        // 为详细信息面板上的所有链接添加事件处理
        const allLinks = detailsDiv.querySelectorAll('a');
        for (const link of allLinks) {
            link.addEventListener('click', function(e) {
                e.stopPropagation(); // 阻止冒泡，避免触发父元素的点击事件
            });
        }
        
        doc.body.appendChild(infoDiv);
    }

    // 清理文档
    function cleanupDocument(doc) {
        // 移除不必要的元素和属性
        
        // 移除所有注释
        const nodeIterator = doc.createNodeIterator(
            doc,
            NodeFilter.SHOW_COMMENT,
            { acceptNode: () => NodeFilter.FILTER_ACCEPT }
        );
        
        let node;
        while (node = nodeIterator.nextNode()) {
            node.parentNode.removeChild(node);
        }
        
        // 移除所有临时消息框和通知
        const tempElementIds = [
            'offline-saver-message', 
            'offline-save-button',
            'force-download-link',
            'force-save-msg',
            'dismiss-message'
        ];
        
        tempElementIds.forEach(id => {
            const tempElement = doc.getElementById(id);
            if (tempElement) {
                tempElement.remove();
            }
        });
        
        // 移除所有带特定类或ID前缀的临时元素
        const tempSelectors = [
            '[id^="force-download-link-"]',
            '[class^="offline-message"]',
            '.offline-saver-notification',
            '[id^="offline-"]'
        ];
        
        tempSelectors.forEach(selector => {
            const elements = Array.from(doc.querySelectorAll(selector));
            // 保留保存信息框
            elements.forEach(el => {
                if (el.id !== 'offline-save-info' && el.id !== 'offline-save-details') {
                    el.remove();
                }
            });
        });
        
        // 移除所有隐藏元素（可选）
        const hiddenElements = Array.from(doc.querySelectorAll('[hidden], [style*="display: none"], [style*="display:none"], [style*="visibility: hidden"], [style*="visibility:hidden"]'));
        for (const element of hiddenElements) {
            // 如果是重要元素，保留
            if (element.tagName === 'TEMPLATE' || element.tagName === 'NOSCRIPT' || element.id === 'offline-save-details') continue;
            element.remove();
        }
    }

    // 获取文档HTML
    function getDocumentHTML(doc) {
        // 添加<!DOCTYPE html>
        const doctype = '<!DOCTYPE html>\n';
        
        // 确保文档中包含正确的UTF-8编码声明
        let metaCharset = doc.querySelector('meta[charset]');
        if (!metaCharset) {
            const head = doc.head || doc.getElementsByTagName('head')[0];
            if (head) {
                metaCharset = doc.createElement('meta');
                metaCharset.setAttribute('charset', 'UTF-8');
                head.insertBefore(metaCharset, head.firstChild);
            }
        } else if (metaCharset.getAttribute('charset') !== 'UTF-8') {
            metaCharset.setAttribute('charset', 'UTF-8');
        }
        
        // 确保离线信息栏正常工作的脚本
        if (GM_getValue('showInfoDisplay', true) === true) {
            const infoScript = doc.createElement('script');
            infoScript.textContent = `
                // 在页面加载完成后为信息栏添加事件
                document.addEventListener('DOMContentLoaded', function() {
                    const infoDiv = document.getElementById('offline-save-info');
                    const detailsDiv = document.getElementById('offline-save-details');
                    const miniInfoDiv = infoDiv ? infoDiv.querySelector('div:not(#offline-save-details)') : null;
                    
                    if (infoDiv && detailsDiv && miniInfoDiv) {
                        // 添加鼠标事件
                        infoDiv.addEventListener('mouseenter', function() {
                            this.style.opacity = '1';
                        });
                        
                        infoDiv.addEventListener('mouseleave', function() {
                            if (detailsDiv.style.display === 'none') {
                                this.style.opacity = '0.5';
                            }
                        });
                        
                        // 添加点击事件（展开/收起）
                        infoDiv.addEventListener('click', function(e) {
                            // 阻止事件冒泡
                            e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
                            
                            // 检查是否点击了关闭按钮
                            if (e.target.id === 'remove-info-bar') {
                                e.preventDefault ? e.preventDefault() : (e.returnValue = false);
                                this.remove();
                                return;
                            }
                            
                            if (detailsDiv.style.display === 'none') {
                                detailsDiv.style.display = 'block';
                                miniInfoDiv.textContent = '↓ 收起信息';
                                this.style.opacity = '1';
                            } else {
                                detailsDiv.style.display = 'none';
                                miniInfoDiv.textContent = '↑ 离线页面信息';
                                this.style.opacity = '0.5';
                            }
                        });
                        
                        // 为详细信息面板上的所有链接添加事件处理
                        const allLinks = detailsDiv.querySelectorAll('a');
                        for (const link of allLinks) {
                            link.addEventListener('click', function(e) {
                                e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
                            });
                        }
                        
                        // 单独为关闭按钮添加事件
                        const closeButton = document.getElementById('remove-info-bar');
                        if (closeButton) {
                            closeButton.addEventListener('click', function(e) {
                                e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
                                e.preventDefault ? e.preventDefault() : (e.returnValue = false);
                                infoDiv.remove();
                            });
                        }
                    }
                });
            `;
            
            // 将脚本添加到文档中
            const head = doc.head || doc.getElementsByTagName('head')[0];
            if (head) {
                head.appendChild(infoScript);
            }
        }
        
        // 获取HTML内容
        const htmlContent = doc.documentElement.outerHTML;
        
        return doctype + htmlContent;
    }

    // 下载HTML文件
    function downloadHTML(html) {
        // 创建文件名：页面标题 + 时间戳
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
        const pageTitle = document.title || 'webpage';
        let filename = sanitizeFilename(pageTitle) + '_' + timestamp + '.html';
        
        // 确保最大长度不超过240字符（避免文件名过长的问题）
        if (filename.length > 240) {
            filename = filename.substring(0, 236) + '.html';
        }
        
        // 检测特殊站点
        const isBaidu = location.hostname.includes('baidu.com') || 
                      document.title.includes('百度') || 
                      (location.href.includes('baidu') && location.href.includes('s?') && location.href.includes('wd=')) ||
                      document.querySelector('meta[name="description"][content*="百度"]') ||
                      document.querySelector('a[href*="www.baidu.com/duty"]') ||
                      document.querySelector('#s_tab') || 
                      document.querySelector('.s_form');
        
        // 检测是否为Discuz论坛或其他可能有问题的网站
        const isDiscuz = document.querySelector('meta[name="generator"][content*="Discuz"]') || 
                        document.querySelector('link[href*="discuz"]') ||
                        document.querySelector('script[src*="discuz"]') ||
                        location.href.includes('discuz') ||
                        document.body.innerHTML.includes('discuz') ||
                        document.body.innerHTML.includes('Discuz') ||
                        document.body.innerHTML.includes('Powered by Discuz');
        
        // 检测Chrome的下载限制
        const hasChromeRestriction = navigator.userAgent.includes('Chrome') && 
                                    document.body.getAttribute('data-download-restriction') === 'true';
        
        // 已知问题网站域名列表
        const problematicDomains = [
            'baidu.com', 
            'sina.com.cn', 
            'weibo.com', 
            'zhihu.com', 
            'tieba.baidu.com',
            'sohu.com',
            '163.com'
        ];
        
        // 检查是否为已知问题网站
        const isProblemSite = problematicDomains.some(domain => location.hostname.includes(domain));
        
        // 对特殊网站显示提示信息
        if (isBaidu || isDiscuz || hasChromeRestriction || isProblemSite) {
            console.log("检测到特殊网站或下载限制，使用强制下载模式");
            showSimpleMessage("检测到特殊网站，使用强制下载模式");
        }

        // 使用强制下载模式
        forceDownload(html, filename);
    }

    // 清理文件名，移除非法字符
    function sanitizeFilename(name) {
        // 替换所有非法字符为下划线
        let safeName = name.replace(/[\\/:*?"<>|]/g, '_');
        // 移除首尾空格
        safeName = safeName.trim();
        // 如果文件名为空，提供默认名称
        if (!safeName) {
            safeName = 'webpage';
        }
        return safeName;
    }
    
    // 强制下载模式
    function forceDownload(html, filename) {
        try {
            const messageDiv = document.getElementById('offline-saver-message');
            if (messageDiv) {
                messageDiv.textContent = '正在使用强制保存方式...';
            }
            
            // 将数据保存为Blob对象
            const blob = new Blob([html], { type: 'text/html;charset=utf-8' });
            const fileSize = blob.size;
            
            // 创建一个通用的下载函数
            const triggerDownload = (url, retry = false) => {
                try {
                    // 创建一个唯一的下载链接ID
                    const linkId = 'force-download-link-' + new Date().getTime();
                    
                    // 创建下载链接
                    const link = document.createElement('a');
                    link.id = linkId;
                    link.href = url;
                    link.download = filename;
                    link.style.position = 'fixed';
                    link.style.opacity = '0';
                    link.style.top = '-100px';
                    document.body.appendChild(link);
                    
                    // 使用事件触发点击，避免直接调用click被浏览器拦截
                    const clickEvent = document.createEvent('MouseEvents');
                    clickEvent.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                    link.dispatchEvent(clickEvent);
                    
                    // 清理
                    setTimeout(() => {
                        if (document.getElementById(linkId)) {
                            document.body.removeChild(link);
                        }
                        URL.revokeObjectURL(url);
                        
                        // 检查是否需要尝试其他下载方法
                        if (retry) {
                            tryOtherMethods();
                        } else {
                            showSuccessMessage('文件已生成，请检查下载列表');
                        }
                    }, 1000);
                } catch (e) {
                    console.error("强制下载失败:", e);
                    if (retry) {
                        tryOtherMethods();
                    } else {
                        // 尝试新窗口下载
                        forceWindowDownload(html, filename);
                    }
                }
            };
            
            // 使用多种URL生成方式，组合下载
            const url = URL.createObjectURL(blob);
            triggerDownload(url, true);
            
            // 尝试其他下载方法的函数
            function tryOtherMethods() {
                // 尝试创建新的iframe强制下载
                try {
                    // 创建隐藏的iframe
                    const iframe = document.createElement('iframe');
                    iframe.style.display = 'none';
                    document.body.appendChild(iframe);
                    
                    // 在iframe中写入内容
                    const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
                    iframeDoc.open();
                    iframeDoc.write(html);
                    iframeDoc.close();
                    
                    // 尝试在iframe中使用下载
                    setTimeout(() => {
                        try {
                            const iframeLink = iframeDoc.createElement('a');
                            iframeLink.href = 'data:text/html;charset=utf-8,' + encodeURIComponent(html);
                            iframeLink.download = filename;
                            iframeDoc.body.appendChild(iframeLink);
                            iframeLink.click();
                            
                            // 清理
                            setTimeout(() => {
                                document.body.removeChild(iframe);
                                showSuccessMessage('iframe模式下载已触发');
                            }, 1000);
                        } catch (e) {
                            document.body.removeChild(iframe);
                            forceWindowDownload(html, filename);
                        }
                    }, 500);
                } catch (e) {
                    console.error("iframe下载失败:", e);
                    forceWindowDownload(html, filename);
                }
            }
        } catch (error) {
            console.error("强制下载方法失败:", error);
            forceWindowDownload(html, filename);
        }
    }
    
    // 方法7：新窗口强制保存
    function forceWindowDownload(html, filename) {
        try {
            const messageDiv = document.getElementById('offline-saver-message');
            if (messageDiv) {
                messageDiv.textContent = '正在使用新窗口保存方式...';
            }
            
            // 打开新窗口并保存内容
            const downloadWindow = window.open('', '_blank');
            if (downloadWindow) {
                // 写入DOCTYPE和内容
                downloadWindow.document.write('<!DOCTYPE html>\n' + html);
                downloadWindow.document.close();
                downloadWindow.document.title = filename.replace('.html', '');
                
                // 添加保存按钮和说明
                const saveBar = downloadWindow.document.createElement('div');
                saveBar.style.cssText = `
                    position: fixed;
                    top: 0;
                    left: 0;
                    right: 0;
                    background: rgba(0, 100, 200, 0.9);
                    color: white;
                    padding: 15px;
                    text-align: center;
                    z-index: 999999999;
                    font-family: Arial, sans-serif;
                    box-shadow: 0 0 10px rgba(0,0,0,0.5);
                `;
                saveBar.innerHTML = `
                    <h3 style="margin:0;font-size:16px;">请点击下方按钮保存此页面</h3>
                    <p style="margin:5px 0;">点击"下载页面"按钮或按Ctrl+S保存</p>
                    <button id="force-save-btn" style="
                        background: #00c853;
                        color: white;
                        border: none;
                        padding: 10px 20px;
                        border-radius: 4px;
                        cursor: pointer;
                        font-weight: bold;
                        margin: 5px;
                    ">下载页面</button>
                    <button id="copy-html-btn" style="
                        background: #0277bd;
                        color: white;
                        border: none;
                        padding: 10px 20px;
                        border-radius: 4px;
                        cursor: pointer;
                        margin: 5px;
                    ">复制HTML到剪贴板</button>
                    <span id="force-save-msg" style="margin-left:10px;display:none;"></span>
                `;
                
                downloadWindow.document.body.insertBefore(saveBar, downloadWindow.document.body.firstChild);
                
                // 添加保存按钮事件
                const saveBtn = downloadWindow.document.getElementById('force-save-btn');
                if (saveBtn) {
                    saveBtn.addEventListener('click', () => {
                        try {
                            // 触发保存对话框
                            const blob = new Blob([downloadWindow.document.documentElement.outerHTML], {type: 'text/html'});
                            const url = downloadWindow.URL.createObjectURL(blob);
                            const link = downloadWindow.document.createElement('a');
                            link.href = url;
                            link.download = filename;
                            link.style.display = 'none';
                            downloadWindow.document.body.appendChild(link);
                            link.click();
                            
                            // 显示成功消息
                            const msgSpan = downloadWindow.document.getElementById('force-save-msg');
                            if (msgSpan) {
                                msgSpan.textContent = '✓ 下载已触发!';
                                msgSpan.style.display = 'inline';
                                msgSpan.style.color = '#4caf50';
                                setTimeout(() => {
                                    msgSpan.textContent = '';
                                    msgSpan.style.display = 'none';
                                }, 3000);
                            }
                            
                            // 清理URL
                            setTimeout(() => {
                                downloadWindow.URL.revokeObjectURL(url);
                                link.remove();
                            }, 1000);
                        } catch (e) {
                            console.error("按钮触发保存失败:", e);
                            // 使用原生保存
                            try {
                                downloadWindow.document.execCommand('SaveAs', true, filename);
                            } catch (ex) {
                                console.error("无法使用SaveAs命令:", ex);
                            }
                        }
                    });
                }
                
                // 添加复制按钮事件
                const copyBtn = downloadWindow.document.getElementById('copy-html-btn');
                if (copyBtn) {
                    copyBtn.addEventListener('click', () => {
                        try {
                            // 复制HTML到剪贴板
                            const htmlContent = '<!DOCTYPE html>\n' + downloadWindow.document.documentElement.outerHTML;
                            
                            // 尝试使用Clipboard API
                            if (downloadWindow.navigator.clipboard && downloadWindow.navigator.clipboard.writeText) {
                                downloadWindow.navigator.clipboard.writeText(htmlContent).then(() => {
                                    showCopySuccess();
                                }).catch(e => {
                                    console.error("Clipboard API失败:", e);
                                    // 回退到GM_setClipboard
                                    GM_setClipboard(htmlContent, 'text/html');
                                    showCopySuccess();
                                });
                            } else {
                                // 回退到GM_setClipboard
                                GM_setClipboard(htmlContent, 'text/html');
                                showCopySuccess();
                            }
                            
                            function showCopySuccess() {
                                const msgSpan = downloadWindow.document.getElementById('force-save-msg');
                                if (msgSpan) {
                                    msgSpan.textContent = '✓ HTML已复制到剪贴板!';
                                    msgSpan.style.display = 'inline';
                                    msgSpan.style.color = '#2196f3';
                                    setTimeout(() => {
                                        msgSpan.textContent = '';
                                        msgSpan.style.display = 'none';
                                    }, 3000);
                                }
                            }
                        } catch (e) {
                            console.error("复制HTML失败:", e);
                        }
                    });
                }
                
                // 显示成功信息
                showSuccessMessage('已在新窗口打开，请使用窗口中的按钮保存');
            } else {
                // 如果无法打开新窗口，则尝试使用剪贴板
                clipboardSave(html, filename);
            }
        } catch (error) {
            console.error("新窗口保存失败:", error);
            clipboardSave(html, filename);
        }
    }
    
    // 方法8：剪贴板保存，末尾保障措施
    function clipboardSave(html, filename) {
        try {
            const messageDiv = document.getElementById('offline-saver-message');
            if (messageDiv) {
                messageDiv.textContent = '尝试复制HTML到剪贴板...';
            }
            
            // 尝试使用GM_setClipboard保存到剪贴板
            GM_setClipboard(html, 'text/html');
            
            // 显示成功提示
            const saveInstructions = `
                <div style="text-align:left;margin-top:15px;">
                    <p><strong>所有下载方法都失败了，已将HTML复制到剪贴板</strong></p>
                    <p>请按照以下步骤手动保存页面：</p>
                    <ol>
                        <li>打开任意文本编辑器（记事本、VS Code等）</li>
                        <li>粘贴剪贴板内容（Ctrl+V）</li>
                        <li>保存为 .html 文件（注意选择UTF-8编码）</li>
                        <li>文件名建议：${filename}</li>
                    </ol>
                </div>
            `;
            
            // 显示完整的保存说明
            const fullMessageDiv = document.createElement('div');
            fullMessageDiv.style.cssText = `
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: rgba(0, 0, 0, 0.85);
                color: white;
                padding: 20px;
                border-radius: 8px;
                max-width: 80%;
                z-index: 999999999;
                box-shadow: 0 0 20px rgba(0,0,0,0.5);
                font-family: Arial, sans-serif;
                font-size: 14px;
                line-height: 1.5;
            `;
            fullMessageDiv.innerHTML = `
                <h3 style="margin-top:0;text-align:center;color:#4caf50;">HTML已复制到剪贴板</h3>
                ${saveInstructions}
                <div style="text-align:center;margin-top:15px;">
                    <button id="dismiss-message" style="
                        background: #2196f3;
                        color: white;
                        border: none;
                        padding: 8px 16px;
                        border-radius: 4px;
                        cursor: pointer;
                        font-weight: bold;
                    ">我知道了</button>
                </div>
            `;
            
            document.body.appendChild(fullMessageDiv);
            
            // 点击关闭按钮
            document.getElementById('dismiss-message').addEventListener('click', () => {
                document.body.removeChild(fullMessageDiv);
            });
            
            // 检查是否可以在新标签打开HTML预览
            try {
                const htmlDataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(html);
                
                // 提供新标签查看选项
                const viewButton = document.createElement('button');
                viewButton.style.cssText = `
                    background: #ff9800;
                    color: white;
                    border: none;
                    padding: 8px 16px;
                    border-radius: 4px;
                    cursor: pointer;
                    margin-left: 10px;
                `;
                viewButton.textContent = '在新标签预览';
                viewButton.onclick = () => {
                    try {
                        GM_openInTab(htmlDataUrl, { active: true });
                    } catch (e) {
                        console.error("无法在新标签打开:", e);
                        window.open(htmlDataUrl, '_blank');
                    }
                };
                
                // 在消息框中添加按钮
                document.getElementById('dismiss-message').parentNode.insertBefore(
                    viewButton, 
                    document.getElementById('dismiss-message')
                );
            } catch (e) {
                console.error("无法创建预览链接:", e);
            }
            
            // 自动在60秒后关闭消息
            setTimeout(() => {
                if (document.body.contains(fullMessageDiv)) {
                    document.body.removeChild(fullMessageDiv);
                }
            }, 60000);
            
            // 尝试使用Notification API
            try {
                GM_notification({
                    title: '页面已复制到剪贴板',
                    text: '所有下载方法失败，网页HTML已复制到剪贴板，请手动保存',
                    timeout: 10000
                });
            } catch (e) {
                console.error("通知API失败:", e);
            }
            
            return true;
        } catch (error) {
            console.error("剪贴板保存失败:", error);
            
            // 完全失败时的最终消息
            showErrorMessage("所有下载方法均失败，请尝试刷新页面或使用其他浏览器");
            
            return false;
        }
    }
    
    // 显示成功消息
    function showSuccessMessage(message = '保存成功！') {
        const messageDiv = document.getElementById('offline-saver-message');
        if (messageDiv) {
            messageDiv.textContent = message;
            messageDiv.style.background = 'rgba(0, 150, 0, 0.8)';
            setTimeout(() => {
                messageDiv.remove();
            }, 3000);
        }
    }

    // 获取资源内容
    function fetchResource(url) {
        return new Promise((resolve, reject) => {
            const requestTimeout = setTimeout(() => {
                reject(new Error(`请求超时: ${url}`));
            }, 15000); // 15秒超时
            
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                timeout: 15000,
                headers: {
                    'Accept': 'text/css,*/*',
                    'Referer': document.location.href
                },
                anonymous: true,
                onload: function(response) {
                    clearTimeout(requestTimeout);
                    if (response.status >= 200 && response.status < 300) {
                        resolve(response.responseText);
                    } else {
                        reject(new Error(`获取资源失败: ${response.status} ${response.statusText}`));
                    }
                },
                onerror: function(error) {
                    clearTimeout(requestTimeout);
                    reject(new Error(`网络错误: ${error}`));
                },
                ontimeout: function() {
                    clearTimeout(requestTimeout);
                    reject(new Error(`请求超时: ${url}`));
                }
            });
        });
    }

    // 获取资源并转换为base64
    function fetchResourceAsBase64(url) {
        return new Promise((resolve, reject) => {
            const requestTimeout = setTimeout(() => {
                reject(new Error(`请求超时: ${url}`));
            }, 15000); // 15秒超时
            
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                responseType: 'arraybuffer',
                timeout: 15000,
                headers: {
                    'Accept': 'image/*,*/*',
                    'Referer': document.location.href
                },
                anonymous: true,
                onload: function(response) {
                    clearTimeout(requestTimeout);
                    if (response.status >= 200 && response.status < 300) {
                        try {
                            const bytes = new Uint8Array(response.response);
                            const binary = bytes.reduce((acc, byte) => acc + String.fromCharCode(byte), '');
                            const base64 = btoa(binary);
                            
                            // 获取MIME类型
                            let mimeType = 'application/octet-stream';
                            const contentType = response.responseHeaders.match(/content-type:\s*([^\s;]+)/i);
                            if (contentType && contentType[1]) {
                                mimeType = contentType[1].toLowerCase();
                            } else {
                                // 尝试从URL推断MIME类型
                                const extension = url.split('.').pop().toLowerCase();
                                const mimeTypes = {
                                    'jpg': 'image/jpeg',
                                    'jpeg': 'image/jpeg',
                                    'png': 'image/png',
                                    'gif': 'image/gif',
                                    'svg': 'image/svg+xml',
                                    'webp': 'image/webp',
                                    'woff': 'font/woff',
                                    'woff2': 'font/woff2',
                                    'ttf': 'font/ttf',
                                    'eot': 'application/vnd.ms-fontobject',
                                    'otf': 'font/otf',
                                    'css': 'text/css',
                                    'js': 'application/javascript'
                                };
                                if (extension in mimeTypes) {
                                    mimeType = mimeTypes[extension];
                                }
                            }
                            
                            resolve(`data:${mimeType};base64,${base64}`);
                        } catch (error) {
                            reject(new Error(`处理资源数据时出错: ${error.message}`));
                        }
                    } else {
                        reject(new Error(`获取资源失败: ${response.status} ${response.statusText}`));
                    }
                },
                onerror: function(error) {
                    clearTimeout(requestTimeout);
                    reject(new Error(`网络错误: ${error}`));
                },
                ontimeout: function() {
                    clearTimeout(requestTimeout);
                    reject(new Error(`请求超时: ${url}`));
                }
            });
        });
    }

    // 移动端适配函数
    function isMobileDevice() {
        return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
    }

    // 如果是移动设备，添加一个浮动按钮
    if (isMobileDevice()) {
        const floatingButton = document.createElement('div');
        floatingButton.id = 'offline-save-button';
        floatingButton.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 50px;
            height: 50px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
            z-index: 9999998;
            cursor: pointer;
            touch-action: manipulation;
        `;
        floatingButton.innerHTML = '💾';
        floatingButton.title = '保存为离线网页';
        floatingButton.addEventListener('click', savePageAsHTML);
        document.body.appendChild(floatingButton);
    }
})(); 